package lib.paxos;

import java.io.Serializable;

import lib.ArgumentValidator;

/**
 * Representation of a sequenceID used in a paxos round
 * @author abhip
 *
 */
public class SequenceID implements Comparable<SequenceID>, Serializable
{
    /**
     * serialVersionUID is a universal version identifier for a Serializable
     * class. Deserialization uses this number to ensure that a loaded class
     * corresponds exactly to a serialized object. If no match is found during
     * deserialization, an InvalidClassException is thrown.
     */
    private static final long serialVersionUID = -7633667938268390171L;

    private int counter;
    private int machineID;

    public SequenceID(int machineID, int counter)
    {
        ArgumentValidator.IsGreaterThan("machineID", machineID, 0);
        ArgumentValidator.IsGreaterThan("counter", counter, 0);

        this.machineID = machineID;
        this.counter = counter;
    }

    @Override
    public int compareTo(SequenceID seqID)
    {
        ArgumentValidator.IsNotNull("seqID", seqID);

        if (this.counter == seqID.counter)
        {
            if (this.machineID == seqID.machineID)
            {
                return 0;
            }
            
            if (this.machineID < seqID.machineID)
            {
                return -1;
            }
            
            return +1;
        }
        
        if (this.counter < seqID.counter)
        {
            return -1;
        }
        
        return +1;
    }

    public int Counter()
    {
        return counter;
    }

    @Override public boolean equals(Object obj)
    {
        // Check for self-comparison
        if (this == obj)
        {
            return true;
        }

        // Check for super type matching
        if (!(obj instanceof SequenceID))
        {
            return false;
        }

        // Cast to native object is now safe
        SequenceID seqID = (SequenceID) obj;

        // Now proper field-by-field comparison can be done
        if (this.compareTo(seqID) == 0)
        {
            return true;
        }

        return false;
    }

    public boolean IsGreaterThan(SequenceID seqID)
    {
        ArgumentValidator.IsNotNull("seqID", seqID);

        if (this.compareTo(seqID) > 0)
        {
            return true;
        }

        return false;
    }

    public boolean IsGreaterThanOrEqualTo(SequenceID seqID)
    {
        ArgumentValidator.IsNotNull("seqID", seqID);

        if (this.compareTo(seqID) >= 0)
        {
            return true;
        }

        return false;
    }

    public boolean IsLessThan(SequenceID seqID)
    {
        ArgumentValidator.IsNotNull("seqID", seqID);

        if (this.compareTo(seqID) < 0)
        {
            return true;
        }

        return false;
    }

    public boolean IsLessThanOrEqualTo(SequenceID seqID)
    {
        ArgumentValidator.IsNotNull("seqID", seqID);

        if (this.compareTo(seqID) <= 0)
        {
            return true;
        }

        return false;
    }

    public int MachineID()
    {
        return machineID;
    }

    @Override public String toString()
    {
        return String.format("machineID: %d, counter: %d", machineID, counter);
    }
}
